package com.wangtao.service;


import com.wangtao.vo.HouseData;
import com.wangtao.vo.SearchResult;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Service
public class SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    public static final Integer ROWS = 10;

    public SearchResult search(String keyWord, Integer page) {
        PageRequest pageRequest = PageRequest.of(page - 1, ROWS); //设置分页参数
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchQuery("title",
                        keyWord).operator(Operator.AND)) // match查询
                .withPageable(pageRequest)
                .withHighlightFields(new HighlightBuilder.Field("title").preTags("<em style=\"color:red\">").postTags("</em>")) // 设置高亮
                .build();
        AggregatedPage<HouseData> housePage =
                this.elasticsearchTemplate.queryForPage(searchQuery,
                        HouseData.class, new SearchResultMapper() {
                            @Override
                            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                                if (response.getHits().totalHits == 0) {
                                    return new AggregatedPageImpl<>(Collections.emptyList(), pageable, 0L);
                                }
                                List<T> list = new ArrayList<>();
                                response.getHits().forEach(searchHit->{
                                    T obj = (T) ReflectUtils.newInstance(clazz);

                                    try {
                                        FieldUtils.writeField(obj, "id", searchHit.getId(), true);
                                    } catch (IllegalAccessException e) {
                                        e.printStackTrace();
                                    }

                                    searchHit.getSourceAsMap().forEach((k,v)-> {

                                        Field field = FieldUtils.getField(clazz, k,true);
                                        if (field == null) {
                                            return;
                                        }
                                        try {
                                            FieldUtils.writeField(obj, k, v, true);
                                        } catch (IllegalAccessException e) {
                                            e.printStackTrace();
                                        }
                                    });
                                    searchHit.getHighlightFields().forEach((k,v)->{
                                        StringBuffer sb = new StringBuffer();
                                        Text[] fragments = v.getFragments();
                                        for (Text fragment : fragments) {
                                            sb.append(fragment.toString());
                                        }

                                        try {
                                            FieldUtils.writeField(obj,k,sb.toString(),true);
                                        } catch (IllegalAccessException e) {
                                            e.printStackTrace();
                                        }

                                    });

                                    list.add(obj);
                                });

                                return new AggregatedPageImpl<>(list,pageable,response.getHits().getTotalHits(),response.getAggregations(), response.getScrollId());
                            }
                        });
        return new SearchResult(housePage.getTotalPages(), housePage.getContent(), null);
    }
}
